home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 10 - 1994 / 10.06 Jun 94 / Drag and Drop next >
Encoding:
Text File  |  1994-05-24  |  10.5 KB  |  429 lines  |  [TEXT/MPS ]

  1. This is all of the source code from the article.  Much of it
  2. had text all through it, so it’s not all directly compilable,
  3. nor does it all read straight through.  It’s a bunch of
  4. snippets and one-liners.
  5.  
  6.  
  7.     if (gHasDragManager) {
  8.         err = InstallTrackingHandler(MyTrackingHandler,
  9.                             theWindow, (void *)dataPtr);
  10.         err = InstallReceiveHandler(MyReceiveDropHandler,
  11.                             theWindow, (void *)dataPtr);
  12.     }
  13.  
  14.  
  15.  
  16.     if (gHasDragManager) {
  17.         RemoveTrackingHandler(MyTrackingHandler, theWindow);
  18.         RemoveReceiveHandler(MyReceiveDropHandler, theWindow);
  19.     }
  20.  
  21.  
  22.     if (gHasDragManager) {
  23.         tLong = DragItem(theWindow);
  24.     }
  25.     else {
  26.         tLong = DragGrayRgn(gRgn, origClick, &limitRect,
  27.                             &slopRect, 0,
  28.                             (DragGrayRgnProcPtr)&FileDragHook);
  29.     }
  30.  
  31.  
  32. long DragItem(WindowPtr theWindow)
  33. {
  34.     ArcFileType            theFile;    //program-specific structure
  35.     DragReference        theDrag;
  36.     RgnHandle            tempRgn;
  37.     Point                    tPt;
  38.     short                    result;
  39.     PromiseHFSFlavor    hfsFlavor;
  40.     OSErr                        err;
  41.     
  42.     theFile = GetSelectedFile(theWindow);
  43.  
  44. //set up to do the drag
  45.     err = NewDrag(&theDrag);
  46.     
  47.     hfsFlavor.fileType = theFile.af_FInfo.fdType;
  48.     hfsFlavor.fileCreator = theFile.af_FInfo.fdCreator;
  49.     hfsFlavor.fdFlags = theFile.af_FInfo.fdFlags;
  50.     hfsFlavor.promisedFlavor = 'VCT1';
  51.     AddDragItemFlavor(theDrag, 1, flavorTypePromiseHFS,
  52.             &hfsFlavor, sizeof(hfsFlavor), flavorNotSaved);
  53.  
  54.     AddDragItemFlavor(theDrag, 1, 'VCT1', nil, 0, 0);
  55.  
  56.     AddDragItemFlavor(theDrag, 1, kDragItem, nil, 0,
  57.             flavorSenderOnly);
  58.  
  59.     SetDragSendProc(theDrag, MySendDataProc, (void *)theWindow);
  60.  
  61.     SetPt(&tPt, 0, 0);
  62.     LocalToGlobal(&tPt);
  63.     OffsetRgn(gRgn, tPt.h, tPt.v);
  64.  
  65.     SetDragItemBounds(theDrag, 1, &(**gRgn).rgnBBox);
  66.  
  67.     tempRgn = NewRgn();
  68.     CopyRgn(gRgn,tempRgn);
  69.     InsetRgn(tempRgn,1,1);
  70.     DiffRgn(gRgn,tempRgn,gRgn);
  71.     DisposeRgn(tempRgn);
  72.  
  73. // do the drag
  74.     result = TrackDrag(theDrag, &gEvent, gRgn);
  75.  
  76. //clean up and return the result
  77.     DisposeDrag(theDrag);
  78.  
  79.     if (result) {
  80.         return (0x80008000);
  81.     }
  82.     else {
  83.         return (0);
  84.     }
  85. }
  86.  
  87.  
  88. pascal OSErr AddDragItemFlavor(DragReference theDragRef,
  89.                                          ItemReference theItemRef,
  90.                                          FlavorType theType,
  91.                                          void *dataPtr,
  92.                                          Size dataSize,
  93.                                          FlavorFlags theFlags);
  94.  
  95.  
  96. #define flavorTypeHFS                'hfs '    // flavor type for HFS data
  97. #define flavorTypePromiseHFS    'phfs'    // flavor type for promised HFS data
  98. #define flavorTypeDirectory    'diry'    // flavor type for AOCE directories
  99.  
  100. struct PromiseHFSFlavor {
  101.     OSType                    fileType;        // file type
  102.     OSType                    fileCreator;    // file creator
  103.     unsigned short    fdFlags;            // Finder flags
  104.     FlavorType        promisedFlavor;    // promised flavor containing an FSSpec
  105. };
  106. typedef struct PromiseHFSFlavor PromiseHFSFlavor;
  107.  
  108.  
  109. enum {
  110.     flavorSenderOnly            = 0x00000001L,    // flavor is available to sender only
  111.     flavorSenderTranslated    = 0x00000002L,    // flavor is translated by sender
  112.     flavorNotSaved                = 0x00000004L,    // flavor should not be saved
  113.     flavorSystemTranslated    = 0x00000100L        // flavor is translated by system
  114. };
  115.  
  116.  
  117.     AddDragItemFlavor(theDrag, 1, 'VCT1', nil, 0, 0);
  118.     
  119.  
  120.     AddDragItemFlavor(theDrag, 1, kDragItem, nil, 0, flavorSenderOnly);
  121.  
  122.  
  123.     SetDragSendProc(theDrag, MySendDataProc, (void *)theWindow);
  124.  
  125.  
  126.     SetPt(&tPt, 0, 0);
  127.     LocalToGlobal(&tPt);
  128.     OffsetRgn(gRgn, tPt.h, tPt.v);
  129.  
  130.  
  131.  
  132.  
  133.     SetDragItemBounds(theDrag, 1, &(**gRgn).rgnBBox);
  134.  
  135.  
  136.     tempRgn = NewRgn();
  137.     CopyRgn(gRgn, tempRgn);
  138.     InsetRgn(tempRgn, 1, 1);
  139.     DiffRgn(gRgn, tempRgn, gRgn);
  140.     DisposeRgn(tempRgn);
  141.  
  142.  
  143.     result = TrackDrag(theDrag, &gEvent, gRgn);
  144.  
  145.  
  146.     err = DisposeDrag(theDrag);
  147.  
  148.  
  149. pascal OSErr MySendDataProc(FlavorType theFlavor, 
  150.                                     void *refCon,
  151.                                     ItemReference theItem, 
  152.                                     DragReference theDrag)
  153. {
  154.     AEDesc        dropLoc;
  155.     FSSpec        target;
  156.     OSErr            err;
  157.     Boolean        wasChanged;
  158.  
  159.     if (theFlavor== 'VCT1') {
  160.         err = GetDropLocation(theDrag, &dropLoc);
  161.  
  162.         err = ResolveAlias(nil, (AliasHandle)dropLoc.dataHandle,
  163.                                          &target, &wasChanged);
  164.         if (err) {
  165.             return (err);
  166.         }
  167.  
  168.         // Decompress item
  169.         err = ExtractSelectedItems((ArchiveWPtr)refCon, &target);
  170.         if (err) {
  171.             return (err);
  172.         }
  173.  
  174.         err = SetDragItemFlavorData(theDrag, theItem, 'VCT1',
  175.                                 (Ptr)&target, sizeof(target), 0L);
  176.     }
  177.  
  178.     return (noErr);
  179. }
  180.  
  181.  
  182.     
  183. pascal OSErr MyTrackingHandler(short message, 
  184.                                 WindowPtr theWindow,
  185.                                 void *handlerRefCon, 
  186.                                 DragReference theDrag)
  187.  
  188. {    short                    result;
  189.     unsigned short    count;
  190.     unsigned short    index;
  191.     unsigned long        flavorFlags;
  192.     unsigned long        attributes;
  193.     ItemReference        theItem;
  194.     RgnHandle            theRgn;
  195.     ArchiveWPtr            dataPtr = (ArchiveWPtr)handlerRefCon;
  196.     ArchiveWPtr            hitDataPtr;
  197.     Point                    theMouse;
  198.     Point                    localMouse;
  199.     Rect                        tRect;
  200.  
  201.     //
  202.     // We decide whether we can accept the data when we are called with
  203.     // a message of dragTrackingEnterHandler. If we can, we set gCanAcceptItems
  204.     // to true.
  205.     //
  206.     
  207.     if ((message != dragTrackingEnterHandler) 
  208.                     && (!gCanAcceptItems)) {
  209.         return (noErr);
  210.     }
  211.  
  212.     GetDragAttributes(theDrag, &attributes);
  213.  
  214.     switch (message) {
  215.         case dragTrackingEnterHandler:
  216.             //
  217.             // by default our window can always accept items
  218.             //
  219.             gCanAcceptItems = true;
  220.             
  221.             //
  222.             // find out how many items have being dragged
  223.             //
  224.             CountDragItems(theDrag, &count);
  225.  
  226.             for (index = 1; index <= count; index++) {
  227.                 //
  228.                 // get the item reference number for the nth item being dragged
  229.                 //
  230.                 GetDragItemReferenceNumber(theDrag, index, &theItem);
  231.                 
  232.                 //
  233.                 // See if a flavor of flavorTypeHFS exists for this drag item
  234.                 // If one does exist, then we can accept this item, so continue
  235.                 // checking the rest of the items.
  236.                 // An item being dragged from the Finder to our window would qualify
  237.                 // as this type.
  238.                 //
  239.                 result = GetFlavorFlags(theDrag, theItem,
  240.                                         flavorTypeHFS, &flavorFlags);
  241.  
  242.                 if (result == noErr) {
  243.                     continue;
  244.                 }
  245.  
  246.                 //
  247.                 // See if a flavor of kDragItem (our proprietary flavor) exists.
  248.                 // If it does and the drag flags indicate we started the drag then
  249.                 // we are simply moving the file in the file list, so we can accept
  250.                 // this type.
  251.                 //
  252.                 result = GetFlavorFlags(theDrag, theItem, 
  253.                                                             kDragItem, &flavorFlags);
  254.  
  255.                 if ((result == noErr) 
  256.                             && (flavorFlags & flavorSenderOnly)) {
  257.                     continue;
  258.                 }
  259.  
  260.                 //
  261.                 // We couldn’t find and flavors that we wanted so we will not
  262.                 // accept the data.
  263.                 //
  264.                 gCanAcceptItems = false;
  265.                 break;
  266.             }
  267.  
  268.             break;
  269.  
  270.         case dragTrackingEnterWindow:
  271.             gCursorInContent = false;
  272.             break;
  273.  
  274.         case dragTrackingInWindow:
  275.             //
  276.             // The user is dragging items over our window.
  277.             // We need to determine if we’ve left our window because the Human
  278.             // Interface Guidelines state that no hiliting is to be done until
  279.             // the user drags outside of the sender window.
  280.             //
  281.             GetDragMouse(theDrag, &theMouse, 0L);
  282.             localMouse = theMouse;
  283.             GlobalToLocal(&localMouse);
  284.  
  285.             if (attributes & dragHasLeftSenderWindow) {
  286.                 //
  287.                 // The user has dragged outside of the sender window so we are now
  288.                 // free to perform hiliting to indicate whether or not the drag
  289.                 // can be accepted by the window.
  290.                 // We check to see if the user is dragging into our window, and
  291.                 // if so, have we shown the drag hilite? If it is appropriate we
  292.                 // will show the drag hilite, meaning the user can drop the drag
  293.                 // items here.
  294.                 // If the user is not dragging in our window, we check to see if
  295.                 // the drag hilite is shown. If it is we hide the drag hilite.
  296.                 //
  297.                 tRect = (**(dataPtr->ArcList)).rView;
  298.                 InsetRect(&tRect, 2, 1);
  299.  
  300.                 if (PtInRect(localMouse, &tRect)) {
  301.                     if (!gCursorInContent) {
  302.                         InsetRect(&tRect, -2, -4);
  303.                         tRgn = NewRgn();
  304.                         RectRgn(theRgn, &tRect);
  305.                         ShowDragHilite(theDrag, theRgn, true);
  306.                         DisposeRgn(theRgn);
  307.                     }
  308.  
  309.                     gCursorInContent = true;
  310.  
  311.                 }
  312.                 else {
  313.                     if (gCursorInContent) {
  314.                         HideDragHilite(theDrag);
  315.                         gCursorInContent = false;
  316.                     }
  317.                 }
  318.             }
  319.  
  320.             //
  321.             // This is our own routine which will return a pointer to a data
  322.             // structure we maintain for each window.
  323.             // We check to see if we are dragging in the sender window. If we
  324.             // are, we call one of our routines to handle hiliting of items in
  325.             // the window, autoscrolling, and other various operations.
  326.             //
  327.             FindDataPtrGivenMousePt(theMouse, &hitDataPtr);
  328.  
  329.             if (hitDataPtr == dataPtr) {
  330.                 HandleSameWindowDrag(theWindow);
  331.             }
  332.  
  333.             break;
  334.  
  335.         case dragTrackingLeaveWindow:
  336.             //
  337.             //    Remove window highlighting, if showing.
  338.             //
  339.             if ((gCursorInContent) 
  340.                         && (attributes & dragHasLeftSenderWindow)) {
  341.                 HideDragHilite(theDrag);
  342.             }
  343.  
  344.             break;
  345.  
  346.         case dragTrackingLeaveHandler:
  347.             break;
  348.     }
  349.  
  350.     return (noErr);
  351. }
  352.  
  353.  
  354. pascal OSErr MyReceiveDropHandler(WindowPtr theWindow, void *handlerRefCon, DragReference theDrag)
  355. {
  356.     unsigned short    items;
  357.     short                index;
  358.     ItemReference    theItem;
  359.     FlavorFlags        theFlags;
  360.     Size                dataSize;
  361.     HFSFlavor        theHFS;
  362.     OSErr                result;
  363.  
  364.     //
  365.     // find out how many items where dragged
  366.     //
  367.     CountDragItems(theDrag, &items);
  368.  
  369.     for (index = 1; index <= items; index++) {
  370.         //
  371.         // Get the item reference number for this drag item so we can find out
  372.         // additional information later on.
  373.         //
  374.         GetDragItemReferenceNumber(theDrag, index, &theItem);
  375.  
  376.         //
  377.         // Get the flavor flags for this object’s flavor of kDragItem.
  378.         // If we can find flags for this flavor, then we know that the drag
  379.         // was completed in the sender window, so what the user did was simply
  380.         // move an item in our file list.
  381.         //
  382.         result = GetFlavorFlags(    theDrag, theItem, kDragItem,
  383.                                                     &theFlags);
  384.         if ((result == noErr) && (flavorFlags & flavorSenderOnly)) {
  385.             //
  386.             // Move the item that the user dragged to the new location in the file list
  387.             //
  388.             MoveListItem(theWindow, 
  389.                     ((ArchiveWPtr)theWindow)->ArcnIndexes, gLastLine);
  390.         }
  391.         else {
  392.             // it wasn’t a drag from one of our windows, so let’s see if a
  393.             // file system object was dragged to our window.
  394.             //
  395.             // Get the flavor flags for this object’s flavor of flavorTypeHFS
  396.             //
  397.             result = GetFlavorFlags(    theDrag, theItem,
  398.                                                         flavorTypeHFS, &theFlags);
  399.  
  400.             if (result == noErr) {
  401.                 //
  402.                 // If we are here then the object contained a flavorTypeHFS so we
  403.                 // need to know how much data it contains (we really do know how
  404.                 // much data is has, but it doesn’t hurt to make this call. 
  405.                 //
  406.                 GetFlavorDataSize(theDrag, theItem, flavorTypeHFS,
  407.                                                 &dataSize);
  408.  
  409.                 //
  410.                 // Get the actual flavor data 
  411.                 //
  412.                 GetFlavorData(    theDrag, theItem, flavorTypeHFS,
  413.                                             &theHFS, &dataSize, 0L);
  414.  
  415.                 //
  416.                 // Make sure the window does not have it’s drag hilite showing
  417.                 //
  418.                 HideDragHilite(theDrag);
  419.  
  420.                 //
  421.                 // Add the dragged files to our archive
  422.                 //
  423.                 AddFilesToArchive(theWindow, &theHFS);
  424.         }
  425.     }
  426.  
  427.     return (noErr);
  428. }
  429.